package am.bll.entity.basic;

import am.exception.ArgumentException;
import am.exception.ArgumentNullException;
import am.exception.InvalidOperationException;

/**
 * 货币金额类, 主要用于货币计算. 
 * 可以也只能精确表示从(-1.0000, +1.0000) * 10^9的所有小数. 
 * 可以表示正负数, 为了方便, 没有在金额表示中加入单位.
 */
public class Money
{
    /**
     * 一个常量, 表示货币金额数值的最大精度, 也即最多精确到小数点后多少位
     */
    public static final int   Precision = 4;

    /**
     * 一个常量, 表示Money类能够表示的最大数值
     */
    public static final Money Max       = new Money("+99999999.9999");

    /**
     * 一个常量, 表示Money类能够表示的最小数值
     */
    public static final Money Min       = new Money("-99999999.9999");
    
    private String integer;
    private String decimal;
    /**
     * 实例化出一个表示具体货币金额的对象, 使用value来构造, 忽略首尾的空格
     * 若超过最大精度将作四舍五入处理, 若精度不足将在末尾补零
     * 
     * @param value 表示金额数值的字符串, 可以带正负号, 不带单位, 例如: -15, 3.43, +4.0, 6.34589 
     *              若超过最大精度会用四舍五入做处理, 例如: 3.123456变为3.1235
     *              若精度不足则在末尾补零, 例如: 3.1变为3.1000
     *              
     * @throws ArgumentNullException 传入null
     * @throws ArgumentException 传入非法的数字字符串
     * @throws InvalidOperationException 转换之后超过边界值
     */

    public Money(String value) throws ArgumentNullException, ArgumentException, InvalidOperationException
    {
        String dot = ".";
        int dotSite = -1;
        value = value.replaceAll( " ", "");
        if(value.charAt(0)=='+')
            value = value.substring(1, value.length());
        if(value.charAt(0)=='-')
        {
            int i;
            for(i = 1;i < value.length() - 1 ;++i)
            {
                if(i != value.length() - 2)
                {
                    if(value.charAt(i) != '0'||value.charAt(i+1)=='.')
                        break;
                }
                    
            }
            if(i!=1)
                value = "-" + value.substring(i,value.length());
        }
        else
        {
            int i;
            for(i = 0; i < value.length() - 1; ++i)
            {
                if(value.charAt(i) != '0' || value.charAt(i+1)=='.')
                {           
                    break;
                }
                if(i == value.length() - 2)
                    continue;
            }
            if(i!=0)
                value = value.substring(i, value.length());
        }
        dotSite = value.indexOf(dot);
        /*当dotSite为-1时，说明参数value中没有小数点，传给this.value是在value后补上.0000*/
        if(dotSite == -1)
        {
           integer = value;
           decimal = "0000";
        }
        else if((value.length() - dotSite) <= 5)
        {
            integer = value.substring(0, dotSite);
            decimal = value.substring(dotSite + 1, value.length());
            int len = decimal.length();
            for(int i = 0; i < 4 - len; ++i)
                decimal += "0";
        }
        else
        {
            integer = value.substring(0, dotSite);
            if(value.length() - dotSite -1 > Precision)
            {
                String tmp = value.substring(dotSite + 1, dotSite + 5);
                if(value.charAt(dotSite + 5) >= '5')
                {                                                    
                    tmp = String.valueOf(Integer.parseInt(tmp)+1);
                }
                if(tmp.length() > 4)
                {
                    if(integer.charAt(0) == '-')                    
                        integer = String.valueOf(Integer.parseInt(integer) - 1);                    
                    else
                        integer = String.valueOf(Integer.parseInt(integer) + 1);
                    decimal = tmp.substring(1, tmp.length());
                    
                }
                else if(tmp.length() != 4)
                {
                    decimal = "";
                    for(int i = 0; i < 4 - tmp.length(); ++i)
                        decimal += "0";
                    decimal += tmp;
                }
                else
                    decimal = tmp;
            }
            else
            {
                decimal = value.substring(dotSite + 1, value.length());
                int len = decimal.length();
                for(int i = 0 ; i < 4 - len; ++i)
                {
                    decimal += "0";
                }
            }
        }
  
    }


    /**
     * 判断value是否是一个合法且可转换的数字字符串, Tester-Doer模式
     * 
     * @param value 待判断的数字字符串
     * 
     * @return 若value不合法或不能转换为数值则返回false, 否则返回true
     */
    static public boolean isValid(String value)
    {
        
        return false;
    }

    /**
     * 获取一个表示金额的字符串, 精确到小数点Precision位(最大精度)
     * 
     * @return 一个金额字符串, 默认省略正号, 例如: 0.3456, -12.0001, 34.3405 
     */
    @Override
    public String toString()
    {
        return toString(Precision);
    }

    /**
     * 获取一个表示金额的字符串, 精确到小数点后fixed位, 若有必要采用四舍五入的策略
     * 
     * @param fixed 一个整数, 取值0~Precision, 表示精确到小数点后多少位
     * 
     * @return 一个字符串, 表示金额, 例如:3.909, 12.05, 39.00
     */

    public String toString(int fixed)
    {
        String dot = ".";
        String value = "";
        long num;
        if(fixed == 0)
        {
            if(decimal.charAt(0) >= '5')
            {
                if(integer.charAt(0) == '-')
                    value = String.valueOf((Integer.parseInt(integer) - 1));
                else
                    value = String.valueOf((Integer.parseInt(integer) + 1));
            }
            else
                value = integer;
        }
        else if(fixed != 4)
        {
            value = integer + decimal.substring(0, fixed);
            num = Integer.parseInt(value);
            if(decimal.charAt(fixed) >= '5')
            {
                if(num > 0)
                    num++;
                else
                    num--;
            
                value = String.valueOf(num);
                value = value.substring(0, value.length() - fixed) + dot;
                String tmp = String.valueOf(num);
                value += tmp.substring(tmp.length() - fixed, tmp.length());
            }
            else
            {
                value = integer + dot + decimal.substring(0, fixed);
            }            
        }
        else
            value = integer + dot + decimal;
        return value;       
    }
    /**
     * 一个加法运算, 计算和另一个金额相加的值并返回
     * 
     * @param addend 另一个加数
     * 
     * @return 两个加数的和, 和的精度依赖于精度最低的那个数, 例如: 3.1 + 0.05 = 3.2
     * 
     * @throws ArgumentNullException 传入null
     * @throws InvalidOperationException 结果超过边界值
     */
    public Money add(Money addend) throws ArgumentNullException, InvalidOperationException
    {
        String dot = ".";
        String value = "0000";
        int nInt;
        int nDec;
        int a = Integer.parseInt(integer);;
        int b = Integer.parseInt(addend.integer);
        char dec[] = value.toCharArray();
        nInt = a + b;
        
        nDec = Integer.parseInt(decimal);
        if(integer.charAt(0) == '-')
            nDec *= -1;
        if(addend.integer.charAt(0) == '-')
            nDec -= Integer.parseInt(addend.decimal);
        else
            nDec += Integer.parseInt(addend.decimal);

        if((nInt > 0 && nDec >0)||(nInt < 0 && nDec < 0) )
        {
            if(nDec > 10000)
            {
                nInt++;
                nDec-=10000;
            }
            if(nDec < -10000)
            {
                nInt--;
                nDec+=10000;
            }
        }
        else if(nInt != 0 && nDec != 0)
        {
            if(nInt > 0)
            {
               nInt--;
               nDec = 10000 + nDec;
            }                
            if(nInt < 0)
            {                
                nInt++;
                nDec = nDec - 10000;
            }
        }
        else
        {
            if(nInt == 923)
                System.out.printf("%d\n", nDec);
            if(nDec > 10000)
            {
                nInt++;
                nDec-= 10000;
            }
            if(nDec < -10000)
            {
                nInt--;
                nDec+=10000;
            }
        }
        if(nInt == 0)
        {
            if(nDec < 0)
                value = "-0";
            else
                value = "0";
        }
        else
            value = String.valueOf(nInt);
        if(nDec < 0)
            nDec *= -1;
        for(int i = 3; i >= 0; --i)
        {
            dec[i] = (char) (nDec % 10 + '0');
            nDec /= 10;
        }
        value += dot + String.valueOf(dec);
        return new Money(value);
    }

    /**
     * 一个减法运算, 计算减去另一个金额的值并返回
     * 
     * @param subtrahend 减数
     * 
     * @return 两个数的差, 差的精度依赖于精度最低的那个数, 例如: 3.1 - 0.05 = 3.0
     * 
     * @throws ArgumentNullException 传入null
     * @throws InvalidOperationException 结果超过边界值
     */
    public Money subtract(Money subtrahend) throws ArgumentNullException, InvalidOperationException
    {
        String sub = subtrahend.toString();
        if(sub.charAt(0) == '-')
        {
            sub = sub.substring(1, sub.length());
        }
        else
        {
            sub = "-" + sub;
        }
        
        Money tmp = new Money(sub);
        return this.add(tmp);
    }

    /**
     * 比较当前金额同另一个金额的数值大小, 返回比较结果
     * 
     * @param compared 与之比较的金额对象
     * 
     * @return 若相等返回0, 若大于compared则返回一个正数, 若小于则返回一个负数
     * 
     * @throws ArgumentNullException 传入null
     */
    public int compare(Money compared) 
    {
        int nInt_a = Integer.parseInt(integer);
        int nInt_b = Integer.parseInt(compared.integer);
        int nDec_a = Integer.parseInt(decimal);
        int nDec_b = Integer.parseInt(compared.decimal);
        if(nInt_a > nInt_b)
        {
            return 1;
        }
        else if(nInt_a < nInt_b)
        {
            return -1;
        }
        else 
        {
            if(nInt_a >= 0)
            {
                if(nDec_a > nDec_b)
                    return 1;
                else if(nDec_a < nDec_b)
                    return -1;
                else
                    return 0;
            }
            else
            {
                if(nDec_a < nDec_b)
                    return 1;
                else if(nDec_a > nDec_b)
                    return -1;
                else
                    return 0;
            }
        }
    }

}
